import re
from pony import orm
from ..models.db import ConsumableNormalize
from .cosine_similary import cosine_similarity_main


class ConsumablesNormalization:
    """基于纯医保库的耗材归一化。"""

    def __init__(self):
        pass

    def consumable_synonym_match(self, input_consumable):
        """
        精准匹配:分别匹配四级目录\关键词别称\别称\三级目录\通用名称。
        :param input_consumable: 输入的耗材名称,这里可能是录入的耗材名称或者是使用后处理之后的耗材名称
        :return: 精准匹配结果
        """
        with orm.db_session:
            # 四级目录\关键词别称\别称精准匹配,输出四级目录
            candidate_consumable_list = list(orm.select(
                consumable.fourth_level_name
                for consumable in ConsumableNormalize
                if
                consumable.fourth_level_name == input_consumable
                or
                consumable.other_name == input_consumable
                or
                consumable.other_key_word == input_consumable
                or
                consumable.other_name == input_consumable
            ))
            if candidate_consumable_list:
                return candidate_consumable_list

            # 三级目录精准匹配,输出三级目录
            candidate_consumable_list = list(orm.select(
                consumable.third_level_name
                for consumable in ConsumableNormalize
                if
                consumable.third_level_name == input_consumable
            ))
            if candidate_consumable_list:
                return candidate_consumable_list

            # 通用名称精准匹配,输出通用名称
            candidate_consumable_list = list(orm.select(
                consumable.common_name
                for consumable in ConsumableNormalize
                if
                consumable.common_name == input_consumable
            ))

            return candidate_consumable_list

    def consumable_contained_match(self, input_consumable):
        """
        精准匹配:分别匹配四级目录\关键词别称\别称\三级目录\通用名称。
        :param input_consumable: 输入的耗材名称,这里一般使用后处理之后的耗材名称
        :return: 精准匹配结果
        """
        with orm.db_session:
            # 四级目录\关键词别称\别称包含匹配,输出四级目录
            candidate_consumable_list = list(orm.select(
                consumable.fourth_level_name
                for consumable in ConsumableNormalize
                if
                (consumable.fourth_level_name and consumable.fourth_level_name in input_consumable)
                or
                (consumable.other_name and consumable.other_name in input_consumable)
                or
                (consumable.other_key_word and consumable.other_key_word in input_consumable)
                or
                (consumable.other_name and consumable.other_name in input_consumable)
            ))
            if candidate_consumable_list:
                return candidate_consumable_list

            # 三级目录包含匹配,输出三级目录
            candidate_consumable_list = list(orm.select(
                consumable.third_level_name
                for consumable in ConsumableNormalize
                if
                (consumable.third_level_name and consumable.third_level_name in input_consumable)
            ))
            if candidate_consumable_list:
                return candidate_consumable_list

            # 通用名称包含匹配,输出通用名称
            candidate_consumable_list = list(orm.select(
                consumable.common_name
                for consumable in ConsumableNormalize
                if
                (consumable.common_name and consumable.common_name in input_consumable)
            ))

            return candidate_consumable_list

    def consumable_fuzzy_match(self, input_consumable):
        """
        精准匹配:耗材归一化库。
        :param input_consumable: 输入字符串
        :return: 只要库里的词条被包含在书瑞条内,则匹配成功,需按长度从大到小排列,取最长的那一个
        """

        with orm.db_session:

            # 四级模糊匹配
            candidate_consumable_fourth_level_list = list(orm.select(
                consumable.fourth_level_name
                for consumable in ConsumableNormalize
            ).order_by(orm.raw_sql('SIMILARITY(consumable.fourth_level_name, $input_consumable) DESC')).limit(10))
            # 三级模糊匹配
            candidate_consumable_third_level_list = list(orm.select(
                consumable.third_level_name
                for consumable in ConsumableNormalize
            ).order_by(orm.raw_sql('SIMILARITY(consumable.third_level_name, $input_consumable) DESC')).limit(10))
            # 通用名模糊匹配
            candidate_consumable_common_name_list = list(orm.select(
                consumable.common_name
                for consumable in ConsumableNormalize
            ).order_by(orm.raw_sql('SIMILARITY(consumable.common_name, $input_consumable) DESC')).limit(10))
            candidate_consumable_list = candidate_consumable_fourth_level_list + candidate_consumable_third_level_list + candidate_consumable_common_name_list
            #
            sorted(candidate_consumable_list, key=lambda x:cosine_similarity_main(x,input_consumable) ,reverse=True)
            return candidate_consumable_list

    def consumable_accurate_match(self, input_consumable, processed_consumable):
        # 如果有录入的耗材名称,尝试用录入耗材品精准匹配同义词,包含三级目录\四级目录关键词\关键词的别称\通用名称\别称,注意这里可能需要做预处理
        if input_consumable:
            normalized_result = self.consumable_synonym_match(input_consumable)
            if normalized_result:
                return normalized_result
        # 用处理后的耗材名称做同义词库精准匹配
        normalized_result = self.consumable_synonym_match(processed_consumable)
        return normalized_result

    def normalize(self, input_consumable):
        """
        耗材归一化主函数。
        :param input: 输入字符串。
        :return:
        """
        # 包含匹配
        normalized_result = self.consumable_contained_match(input_consumable)
        if normalized_result:
            return normalized_result
        # 模糊匹配
        normalized_result = self.consumable_fuzzy_match(input_consumable)
        if normalized_result:
            return normalized_result
        else:
            return []
